package com.slipper.codeless.controller;

import com.alibaba.excel.EasyExcel;
import com.google.gson.reflect.TypeToken;
import com.slipper.codeless.resolve.query.Condition;
import com.slipper.codeless.service.CodelessService;
import com.slipper.common.bo.UserDetail;
import com.slipper.constants.Constants;
import com.slipper.core.excel.ExcelReadListener;
import com.slipper.core.excel.StringNumberConverter;
import com.slipper.core.file.FileServiceUtil;
import com.slipper.core.gson.GsonUtil;
import com.slipper.core.message.MessageUtil;
import com.slipper.core.message.Topic;
import com.slipper.exception.CommonException;
import com.slipper.system.affix.bo.AffixItemBO;
import com.slipper.system.affix.service.AffixItemService;
import com.slipper.system.codeless.bo.*;
import com.slipper.system.codeless.service.*;
import com.slipper.groovy.service.GroovyService;
import com.slipper.groovy.vo.Message;
import com.slipper.core.tree.TreeInfo;
import com.slipper.core.tree.TreeUtil;
import com.slipper.system.dictionary.service.DictionaryDataService;
import com.slipper.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;

@RestController
@RequestMapping("/codeless")
public class CodelessApiController {
    private static final Logger logger = LoggerFactory.getLogger(CodelessApiController.class);

    @Resource
    public CodelessService codelessService;
    @Resource
    public DataModelService dataModelService;
    @Resource
    public DataFieldService dataFieldService;
    @Resource
    public DataTableService dataTableService;
    @Resource
    public DataFormService dataFormService;
    @Resource
    public PageCompService pageCompService;
    @Resource
    public PageCompButtonService pageCompButtonService;
    @Resource
    private TemplateService templateService;
    @Resource
    private AffixItemService affixItemService;
    @Resource
    private DictionaryDataService dictionaryDataService;

    /**
     * 查询页面组件表单数据
     * @param dataModelId 数据模型ID
     * @param data 查询条件
     */
    @PostMapping("/data-model/{dataModelId}/data")
    public String queryDataModelData(
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(dataModelId)) return ResultUtil.failureResult("参数错误！");
        return ResultUtil.successResult(codelessService.queryByParam(dataModelId, data));
    }

    /**
     * 查询页面组件表单数据
     * @param dataModelId 数据模型ID
     * @param data 查询条件
     */
    @PostMapping("/data-model/{dataModelId}/list")
    public String queryDataModelList(
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(dataModelId)) return ResultUtil.failureResult("参数错误！");
        return ResultUtil.successResult(codelessService.queryList(dataModelId, data));
    }

    /**
     * 查询数据模型数据
     * @param dataModelId 数据模型ID
     * @param data 查询条件
     */
    @PostMapping("/data-model/{dataModelId}/page")
    public String queryDataModelPage(
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(dataModelId)) return ResultUtil.failureResult("参数错误！");
        return ResultUtil.successResult(codelessService.queryPage(dataModelId, data));
    }

    /**
     * 查询数据模型数据
     * @param dataModelId 数据模型ID
     * @param data 查询条件
     */
    @PostMapping("/data-model/{dataModelId}/distinct")
    public String queryDataModelDistinct(
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(dataModelId)) return ResultUtil.failureResult("参数错误！");
        return ResultUtil.successResult(codelessService.queryDistinctPage(dataModelId, data));
    }

    /**
     * 查询页面组件树形控件数据
     * @param pageCompId 页面组件ID
     */
    @PostMapping("/page-comp/{pageCompId}/tree")
    public String queryPageCompTree(@PathVariable("pageCompId") String pageCompId) {
        if (Tool.isBlank(pageCompId)) return ResultUtil.failureResult("参数错误！");

       
        codelessService.checkPermit(Constants.getCurrentUser(), pageCompId);

        PageCompBO pageComp = pageCompService.queryBy(pageCompId);
        if (pageComp == null || Tool.isBlank(pageComp.getDataTableId())) {
            return ResultUtil.failureResult("页面组件未配置数据表格信息！");
        }

        List<DataFieldBO> dataFieldList = dataFieldService.queryListBy(pageComp.getTreeDataModelId());
        TreeInfo treeInfo = new TreeInfo("根节点");
        treeInfo.setRootId(Constants.ROOT_ID);

        DataFieldBO idField = getField(pageComp.getTreeNodeFieldId(), dataFieldList);
        DataFieldBO pidField = getField(pageComp.getTreeParentFieldId(), dataFieldList);
        DataFieldBO textField = getField(pageComp.getTreeShowFieldId(), dataFieldList);
        DataFieldBO sortField = getField(pageComp.getTreeOrdinalFieldId(), dataFieldList);
        sortField = sortField == null ? textField : sortField;

        treeInfo.setIdField(idField == null ? "" : idField.getFieldName());
        treeInfo.setPidField(pidField == null ? "" : pidField.getFieldName());
        treeInfo.setTextField(textField == null ? "" : textField.getFieldName());
        treeInfo.setSortField(sortField == null ? "" : sortField.getFieldName());

        DataModelBO dataModel = dataModelService.queryBy(pageComp.getTreeDataModelId());
        List<Map<String, Object>> dataList = codelessService.queryList(
                dataModel,
                null,
                pageComp.getPrivilegeList(),
                null,
                new HashMap<>());
        if (sortField != null
                && !DataFieldBO.FIELD_TYPE_INTEGER.equals(sortField.getFieldType())
                && !DataFieldBO.FIELD_TYPE_NUMERIC.equals(sortField.getFieldType())
                && !DataFieldBO.FIELD_TYPE_DATETIME.equals(sortField.getFieldType())) {
            treeInfo.setSortField(sortField.getFieldName() + "_ordinal_field_name");
            if (Tool.isNotBlank(pageComp.getTreeOrdinalFieldId())) {
                String finalSortField = sortField.getFieldName();
                dataList.sort((o1, o2) -> {
                    if (o1 == null && o2 == null) return 0;

                    if (o1 == null || o1.get(finalSortField) == null) {
                        return -1;
                    }
                    if (o2 == null || o2.get(finalSortField) == null) {
                        return 1;
                    }
                    return o1.get(finalSortField).toString().compareTo(o2.get(finalSortField).toString());
                });
                int i = 0;
                for (Map<String, Object> item : dataList) {
                    item.put(sortField.getFieldName() + "_ordinal_field_name", ++i);
                }
            }
        }

        return ResultUtil.successResult(TreeUtil.buildTree(treeInfo, dataList, "asc"));
    }

    private DataFieldBO getField(String id, List<DataFieldBO> dataFieldList) {
        if (Tool.isBlank(id)) return null;

        for (DataFieldBO field : dataFieldList) {
            if (id.equals(field.getId())) {
                return field;
            }
        }
        return null;
    }

    /**
     * 查询页面组件表格数据
     * @param pageCompId 页面组件ID
     * @param data 查询条件
     */
    @PostMapping("/page-comp/{pageCompId}/page")
    public String queryPageCompPage(
            @PathVariable("pageCompId") String pageCompId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(pageCompId)) return ResultUtil.failureResult("参数错误！");

        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, pageCompId);

        PageCompBO pageComp = pageCompService.queryBy(pageCompId);
        if (pageComp == null || Tool.isBlank(pageComp.getDataTableId())) {
            return ResultUtil.failureResult("页面组件未配置数据表格信息！");
        }

        DataTableBO dataTable = dataTableService.queryBy(pageComp.getDataTableId());
        if (dataTable == null) return ResultUtil.failureResult("此表格配置信息不存在！");

        if (Tool.isBlank(dataTable.getModelId())) {
            return ResultUtil.failureResult("表格[" + dataTable.getName() + "]数据模型归属未配置！");
        }
        return ResultUtil.successResult(codelessService.queryPage(
                pageComp,
                dataTable.getModelId(),
                pageComp.getFilterList(),
                dataTable.getPrivilegeList(),
                dataTable.getOrdinalList(),
                data));
    }

    /**
     * 查询页面组件表格数据
     */
    @PostMapping("/{dataTableId}/page")
    public String queryTablePage(
            @PathVariable("dataTableId") String dataTableId,
            @RequestBody Map<String, Object> data) {
        Constants.getCurrentUser(true);

        DataTableBO dataTable = dataTableService.queryBy(dataTableId);
        if (dataTable == null) return ResultUtil.failureResult("此表格配置信息不存在！");

        if (Tool.isBlank(dataTable.getModelId())) {
            return ResultUtil.failureResult("表格[" + dataTable.getName() + "]数据模型归属未配置！");
        }
        return ResultUtil.successResult(codelessService.queryPage(
                null,
                dataTable.getModelId(),
                null,
                dataTable.getPrivilegeList(),
                dataTable.getOrdinalList(),
                data));
    }

    /**
     * 保存页面组件树节点数据
     */
    @PostMapping("/{menuId}/{dataModelId}/save")
    public String treeSave(
            @PathVariable("menuId") String menuId,
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(menuId, dataModelId)) throw new CommonException("参数错误！");

        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, menuId);
        String result = ResultUtil.saveResult(codelessService.saveByDataModelId(dataModelId, user, data, null));
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);
        return result;
    }

    /**
     * 保存页面组件数据
     */
    @PostMapping("/{menuId}/{dataModelId}/saveModel")
    public String saveModel(
            @PathVariable("menuId") String menuId,
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(menuId, dataModelId)) throw new CommonException("参数错误！");

        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, menuId);
        int result = codelessService.saveByDataModelId(dataModelId, user, data, null);
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);

        return result > 0 ? ResultUtil.successResult("修改成功！") : ResultUtil.failureResult("修改失败！");
    }

    /**
     * 保存页面组件数据
     */
    @PostMapping("/{menuId}/{buttonId}/{dataModelId}/saveModel")
    public String saveModel(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(menuId, dataModelId)) throw new CommonException("参数错误！");

        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, menuId, buttonId);
        int result = codelessService.saveByDataModelId(dataModelId, user, data, buttonId);
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);

        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        return result > 0 ? ResultUtil.successResult(button.getName() + "成功！")
                : ResultUtil.failureResult(button.getName() + "失败！");
    }

    /**
     * 保存页面组件数据
     */
    @PostMapping("/{menuId}/{buttonId}/{dataModelId}/saveModelList")
    public String saveModelList(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody List<Map<String, Object>> dataList) {
        if (Tool.isBlank(menuId, dataModelId)) throw new CommonException("参数错误！");

        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, menuId, buttonId);
        int result = codelessService.saveByDataModelId(dataModelId, user, dataList, buttonId);
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);

        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        return result > 0 ? ResultUtil.successResult(button.getName() + "成功！")
                : ResultUtil.failureResult(button.getName() + "失败！");
    }

    /**
     * 保存页面组件数据
     */
    @PostMapping("/{menuId}/{buttonId}/{dataTableId}/saveTableList")
    public String saveTableList(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            @PathVariable("dataTableId") String dataTableId,
            @RequestBody List<Map<String, Object>> dataList) {
        if (Tool.isBlank(menuId, dataTableId) || dataList == null || dataList.isEmpty()) {
            throw new CommonException("参数错误！");
        }

        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, menuId, buttonId);
        int result = codelessService.saveByDataTableId(dataTableId, user, dataList);
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);

        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        return result > 0 ? ResultUtil.successResult(button.getName() + "成功！")
                : ResultUtil.failureResult(button.getName() + "失败！");
    }

    /**
     * 保存表单数据
     */
    @PostMapping("/{menuId}/{buttonId}/{dataFormId}/saveForm")
    public String saveForm(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            @PathVariable("dataFormId") String dataFormId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(menuId) || Tool.isBlank(dataFormId)) throw new CommonException("参数错误！");
        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, menuId, buttonId);

        DataFormBO dataForm = dataFormService.queryBy(dataFormId);
        if (dataForm == null) throw new CommonException("参数错误！");
        int result = codelessService.saveByDataModelId(dataForm.getModelId(), user, data, buttonId);
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);

        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        if (Constants.YES.equals(button.getSaveAndRun()) && Tool.isNotBlank(button.getExecuteScriptId())) {
            GroovyService.runById(button.getExecuteScriptId(), data);
        }

        return result > 0 ? ResultUtil.successResult(button.getName() + "成功！")
                : ResultUtil.failureResult(button.getName() + "失败！");
    }

    /**
     * 保存表单数据
     */
    @PostMapping("/{menuId}/{buttonId}/{dataFormId}/saveFormList")
    public String saveFormList(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            @PathVariable("dataFormId") String dataFormId,
            @RequestBody List<Map<String, Object>> dataList) {
        if (Tool.isBlank(menuId) || Tool.isBlank(dataFormId)) throw new CommonException("参数错误！");
        if (dataList == null || dataList.isEmpty()) throw new CommonException("参数错误！");
        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, menuId, buttonId);

        DataFormBO dataForm = dataFormService.queryBy(dataFormId);
        if (dataForm == null) throw new CommonException("参数错误！");
        int result = codelessService.saveByDataModelId(dataForm.getModelId(), user, dataList, buttonId);
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);

        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        if (Constants.YES.equals(button.getSaveAndRun()) && Tool.isNotBlank(button.getExecuteScriptId())) {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("dataList", dataList);
            GroovyService.runById(button.getExecuteScriptId(), dataMap);
        }

        return result > 0 ? ResultUtil.successResult(button.getName() + "成功！")
                : ResultUtil.failureResult(button.getName() + "失败！");
    }

    /**
     * 保存表单数据
     */
    @PostMapping("/{menuId}/{buttonId}/{pageId}/savePage")
    public String savePage(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            @PathVariable("pageId") String pageId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(menuId, buttonId, pageId)) throw new CommonException("参数错误！");
        if ("visual".equals(buttonId)) buttonId = null;

        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, menuId, buttonId, pageId);
        codelessService.saveByPageId(user, pageId, buttonId, data, null);
        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        if (Constants.YES.equals(button.getSaveAndRun()) && Tool.isNotBlank(button.getExecuteScriptId())) {
            GroovyService.runById(button.getExecuteScriptId(), data);
        }

        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);
        return ResultUtil.successResult("保存成功。");
    }

    /**
     * 删除页面组件数据
     */
    @PostMapping("/{menuId}/{dataModelId}/delete")
    public String delete(
            @PathVariable("menuId") String menuId,
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(menuId, dataModelId)) throw new CommonException("参数错误！");
        codelessService.checkPermit(Constants.getCurrentUser(), menuId);
        String result = ResultUtil.deleteResult(codelessService.deleteByDataModelId(dataModelId, data));
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);
        return result;
    }

    /**
     * 删除页面组件数据
     */
    @PostMapping("/{menuId}/{buttonId}/{dataModelId}/delete")
    public String delete(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            @PathVariable("dataModelId") String dataModelId,
            @RequestBody Map<String, Object> data) {
        if (Tool.isBlank(menuId, buttonId, dataModelId)) throw new CommonException("参数错误！");

        codelessService.checkPermit(Constants.getCurrentUser(), menuId, buttonId);
        String result = ResultUtil.deleteResult(codelessService.deleteByDataModelId(dataModelId, data));
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);
        return result;
    }

    /**
     * 下载页面组件上传数据的模板
     */
    @PostMapping("/{menuId}/{buttonId}/{dataTableId}/downloadTpl")
    public void downloadTpl(
            @PathVariable("menuId") String menuId,
            @PathVariable("dataTableId") String dataTableId,
            @PathVariable("buttonId") String buttonId,
            HttpServletResponse response) throws IOException {
        if (Tool.isBlank(menuId, dataTableId, buttonId)) throw new CommonException("参数错误！");

        codelessService.checkPermit(Constants.getCurrentUser(), menuId, buttonId);
        DataTableBO dataTable = dataTableService.queryBy(dataTableId);
        if (dataTable == null) throw new CommonException("此表格配置信息不存在！");

        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        if (button == null) throw new CommonException("按钮配置信息不存在！");

        String tplName = dataTable.getName() + ".xlsx";
        List<DataFieldBO> dataFieldList = dataFieldService.queryListBy(dataTable.getModelId());
        List<Map<String, Object>> fieldList = getFieldList(dataTable, dataFieldList);

        List<List<String>> headList = new ArrayList<>();
        List<Integer> widthList = new ArrayList<>();
        fieldList.forEach(field -> {
            List<String> headItem = new ArrayList<>();
            headItem.add((String) field.get("name"));
            headList.add(headItem);
            widthList.add((int) field.get("width"));
        });
        FileUtil.downloadExcel(response, tplName, headList, widthList, new ArrayList<>());
    }

    /**
     * 下载页面组件上传数据的模板
     */
    @PostMapping("/{menuId}/{buttonId}/downloadTpl")
    public void downloadTpl(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            HttpServletResponse response) throws Exception {
        if (Tool.isBlank(menuId, buttonId)) throw new CommonException("参数错误！");

        codelessService.checkPermit(Constants.getCurrentUser(), menuId, buttonId);

        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        if (button == null) throw new CommonException("按钮配置信息不存在！");

        String tplName = (Tool.isBlank(button.getTplName()) ? button.getName() : button.getTplName())  + ".xlsx";

        if (PageCompButtonBO.TPL_TYPE_CUSTOM.equals(button.getTplType())) {
            List<DataFieldBO> dataFieldList = dataFieldService.queryListBy(button.getModelId());
            List<Map<String, Object>> fieldList = getFieldList(button, dataFieldList);

            List<List<String>> headList = new ArrayList<>();
            List<Integer> widthList = new ArrayList<>();
            fieldList.forEach(field -> {
                List<String> headItem = new ArrayList<>();
                headItem.add((String) field.get("name"));
                headList.add(headItem);
                widthList.add((int) field.get("width"));
            });
            FileUtil.downloadExcel(response, tplName, headList, widthList, new ArrayList<>());
        } else {
            TemplateBO template = templateService.queryBy(button.getTplFileId());
            AffixItemBO affixItem = this.affixItemService.queryBy(template.getFileId());
            FileUtil.download(response, tplName, FileServiceUtil.readFile(affixItem.getSavePath()));
        }
    }

    /**
     * 保存导入数据
     */
    @PostMapping("/{menuId}/{buttonId}/{dataTableId}/importXls")
    public String importXls(
            @PathVariable("menuId") String menuId,
            @PathVariable("dataTableId") String dataTableId,
            @PathVariable("buttonId") String buttonId,
            @RequestParam("file") MultipartFile file,
            @RequestParam("dataList") String dataListStr) {
        if (file == null) {
            return ResultUtil.failureResult("上传文件不存在！");
        }

        UserDetail user = Constants.getCurrentUser();
        codelessService.checkPermit(user, menuId, buttonId);
        DataTableBO dataTable = dataTableService.queryBy(dataTableId);
        if (dataTable == null) throw new CommonException("此表格配置信息不存在！");

        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        if (button == null) throw new CommonException("按钮配置信息不存在！");

        try {
            ExcelReadListener listener = new ExcelReadListener();
            EasyExcel.read(file.getInputStream(), listener)
                    .registerConverter(new StringNumberConverter())
                    .sheet()
                    .headRowNumber(1)
                    .doRead();

            if (PageCompButtonBO.TPL_TYPE_SCRIPT.equals(button.getTplType())) {
                List<Map<String, Object>> dataMapList = new ArrayList<>();
                Map<Integer, String> headMap = listener.getHeadList().getFirst();

                for (int i=0; i<listener.getSheetDataList().size(); i++) {
                    dataMapList.addAll(convert(headMap, listener.getSheetDataList().get(i)));
                }

                List<Map<String, Object>> dataList = Collections.emptyList();
                if (Tool.isNotBlank(dataListStr)) {
                    Type type = new TypeToken<List<Map<String, Object>>>(){}.getType();
                    dataList = GsonUtil.fromJson(dataListStr, type);
                }
                Map<String, Object> dataMap = new HashMap<>();
                dataMap.put("dataList", dataList);
                dataMap.put("importList", dataMapList);
                Object result = GroovyService.runById(button.getExecuteScriptId(), dataMap);
                if (result instanceof Message message) {
                    if (message.isSuccess()) {
                        return ResultUtil.successResult(message.getMessage());
                    } else {
                        return ResultUtil.failureResult("-1", message.getMessage());
                    }
                }
                return ResultUtil.successResult("数据导入成功。");
            }

            Map<Integer, DataFieldBO> headMap = new HashMap<>();
            listener.getHeadList().getFirst().forEach((key, value) -> {
                if (Tool.isBlank(value)) return;

                if (Tool.isNotBlank(button.getButtonId())) {
                    List<DataFieldBO> dataFieldList = dataFieldService.queryListBy(dataTable.getModelId());
                    dataTable.getFieldList().stream()
                            .filter(field ->
                                    (value.equals(field.getAliasName())
                                            && !"update_time".equalsIgnoreCase(field.getFieldName())
                                            && !"create_time".equalsIgnoreCase(field.getFieldName()))
                                        || value.equals(field.getFieldName()))
                            .findFirst()
                            .flatMap(field -> dataFieldList.stream()
                                    .filter(item -> item.getId().equals(field.getFieldId()))
                                    .findFirst())
                            .ifPresent(fieldItem -> headMap.put(key, fieldItem));
                } else {
                    List<DataFieldBO> dataFieldList = dataFieldService.queryListBy(button.getModelId());
                    Type type = new TypeToken<List<Map<String, Object>>>(){}.getType();
                    List<Map<String, Object>> fieldMapList = GsonUtil.fromJson(button.getFieldsJson(), type);
                    fieldMapList.stream()
                            .filter(field -> value.equals(field.get("name")))
                            .findFirst()
                            .flatMap(field -> dataFieldList.stream()
                                    .filter(item -> item.getId().equals(field.get("id")))
                                    .findFirst())
                            .ifPresent(fieldItem -> headMap.put(key, fieldItem));
                }
            });

            StringBuilder builder = new StringBuilder();
            List<Map<String, Object>> dataMapList = new ArrayList<>();
            for (int i=0; i<listener.getSheetDataList().size(); i++) {
                dataMapList.addAll(checkAndConvert(
                        headMap,
                        listener.getSheetDataList().get(i),
                        "第 " + (i + 1) + " 个 sheet ",
                        builder));
            }
            if (!builder.isEmpty()) {
                return ResultUtil.failureResult("2", builder.substring(3));
            }
            if (dataMapList.isEmpty()) {
                return ResultUtil.failureResult("2", "未能从excel中获取到数据，可能原因：1、文件无数据，2、表头内容与字段不匹配！");
            }

            String modelId = Tool.isBlank(button.getButtonId()) ? button.getModelId() : dataTable.getModelId();
            codelessService.batchInsert(dataModelService.queryBy(modelId).getCode(), user, dataMapList, true);
            MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);
            return ResultUtil.successResult("数据导入成功。");
        } catch (Exception e) {
            logger.error("数据导入出错!", e);
            String message = e.getMessage();
            if (message != null && message.startsWith("未提交要更新的数据！")) {
                message = "未能从excel中获取到数据，可能原因：1、文件无数据，2、表头内容与字段不匹配！";
            }
            return ResultUtil.failureResult("2", "导入错误：" + message);
        }
    }

    private List<Map<String, Object>> checkAndConvert(
            Map<Integer, DataFieldBO> headMap,
            List<Map<Integer, String>> dataList,
            String prefix,
            StringBuilder message) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (int i=0; i<dataList.size(); i++) {
            String rowPrefix = "@@@" + prefix + "第 " + (i + 2) + " 行";

            Map<Integer, String> data = dataList.get(i);
            Map<String, Object> result = new HashMap<>();
            data.forEach((key, value) -> {
                String colPrefix = rowPrefix + "第 " + ((char) ('A' + key)) + " 列：";
                DataFieldBO dataField = headMap.get(key);
                if (dataField == null) return;

                if (Constants.YES.equals(dataField.getRequired()) && Tool.isBlank(value)) {
                    message.append(colPrefix).append("不能为空！");
                    return;
                }
                if (Tool.isNotBlank(value)
                        && DataFieldBO.FIELD_TYPE_VARCHAR.equals( dataField.getFieldType())
                        && Constants.YES.equals(dataField.getEnumerate())
                        && Arrays.stream(dataField.getEnumerateValue().split(","))
                            .noneMatch(item -> item.equals(value))) {
                    message.append(colPrefix)
                            .append("数据不正确，可选值[")
                            .append(dataField.getEnumerateValue()).append("]！");
                    return;
                }
                if (Tool.isNotBlank(value)
                        && dataField.getFieldSize() != null
                        && value.length() > dataField.getFieldSize()) {
                    message.append(colPrefix).append("长度必须小于个").append(dataField.getFieldSize()).append("字符！");
                    return;
                }
                if (Tool.isNotBlank(value)
                        && DataFieldBO.FIELD_TYPE_INTEGER.equals(dataField.getFieldType())
                        && !value.matches("\\d+")) {
                    message.append(colPrefix).append("必须为整数！");
                    return;
                }
                if (Tool.isNotBlank(value)
                        && DataFieldBO.FIELD_TYPE_NUMERIC.equals(dataField.getFieldType())
                        && !value.matches("^(-?\\d+)(\\.\\d+)?$")) {
                    message.append(colPrefix).append("必须为小数！");
                    return;
                }

                if (Tool.isBlank(value)) return;

                if (DataFieldBO.FIELD_TYPE_RELATION.equals(dataField.getFieldType())) {
                    if (DataFieldBO.RELEVANCE_TYPE_MODEL.equals(dataField.getRelevanceType())) {
                        DataFieldRelevanceBO relevance = dataField.getRelevanceList().getFirst();
                        Map<String, Object> paramMap = new HashMap<>();
                        paramMap.put("inputParamList", List.of(Arrays.asList(relevance.getShowFieldName(), Condition.MATCH_MODE_EQU, value)));
                        Map<String, Object> dataMap = codelessService.queryByParam(relevance.getDataModelId(), paramMap);
                        if (dataMap == null || dataMap.isEmpty() || Tool.isBlank(dataMap.get(relevance.getNodeFieldName()))) {
                            message.append(colPrefix).append(dataField.getShowName()).append("不存在！");
                            return;
                        }
                        result.put(dataField.getFieldName(), dataMap.get(relevance.getNodeFieldName()));
                    } else if (Tool.isNotBlank(dataField.getRelevanceType())
                            && dataField.getRelevanceType().startsWith(DataFieldBO.RELEVANCE_TYPE_DICT)) {
                        String dictKey = dictionaryDataService.queryDictKey(dataField.getRelevanceDict(), value);
                        if (Tool.isBlank(dictKey)) {
                            message.append(colPrefix).append(dataField.getShowName()).append("不存在！");
                            return;
                        }
                        result.put(dataField.getFieldName(), dictKey);
                    } else {
                        result.put(dataField.getFieldName(), value);
                    }
                } else {
                    result.put(dataField.getFieldName(), value);
                }
            });

            if (!result.isEmpty()) {
                resultList.add(result);
            }
        }

        return resultList;
    }

    private List<Map<String, Object>> convert(Map<Integer, String> headMap, List<Map<Integer, String>> dataList) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Map<Integer, String> data : dataList) {
            Map<String, Object> result = new HashMap<>();
            data.forEach((key, value) -> {
                String fieldName = headMap.get(key);
                if (Tool.isBlank(value)) return;
                result.put(fieldName, value);
            });

            resultList.add(result);
        }

        return resultList;
    }

    /**
     * 导出数据
     */
    @PostMapping("/{menuId}/{buttonId}/exportXls")
    public void exportXls(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            @RequestBody Map<String, Object> data,
            HttpServletResponse response) throws IOException {
        if (Tool.isBlank(menuId, buttonId)) throw new CommonException("参数错误！");
        codelessService.checkPermit(Constants.getCurrentUser(), menuId, buttonId);

        PageCompButtonBO button = pageCompButtonService.queryBy(buttonId);
        if (button == null) {
            throw new CommonException("按钮配置信息不存在！");
        }

        PageCompBO pageComp = pageCompService.queryBy(button.getCompId());
        if (pageComp == null) {
            throw new CommonException("页面组件信息不存在！");
        }

        DataTableBO dataTable = dataTableService.queryBy(pageComp.getDataTableId());
        if (dataTable == null) {
            throw new CommonException("此表格配置信息不存在！");
        }

        DataModelBO dataModel = dataModelService.queryBy(dataTable.getModelId());
        if (dataModel == null) {
            throw new CommonException("表格[" + dataTable.getName() + "]数据模型信息不存在！");
        }

        if (Tool.isNotBlank(button.getButtonId())) {
            List<DataFieldBO> dataFieldList = dataFieldService.queryListBy(dataTable.getModelId());
            List<Map<String, Object>> fieldList = getFieldList(dataTable, dataFieldList);
            this.doExport(pageComp, dataModel, dataTable, fieldList, data, response);
        } else {
            GroovyService.runById(button.getExecuteScriptId(), data);
        }
    }

    private void doExport(
            PageCompBO pageComp,
            DataModelBO dataModel,
            DataTableBO dataTable,
            List<Map<String, Object>> fieldList,
            Map<String, Object> data,
            HttpServletResponse response) throws IOException {
        List<List<String>> headList = new ArrayList<>();
        List<Integer> widthList = new ArrayList<>();
        fieldList.forEach(field -> {
            List<String> headItem = new ArrayList<>();
            headItem.add((String) field.get("name"));
            headList.add(headItem);
            int width = (int) field.get("width");
            widthList.add(width == 0 ? 100 : Math.abs(width));
        });

        List<Map<String, Object>> dataList = codelessService.queryList(
                dataModel,
                pageComp.getFilterList(),
                dataTable.getPrivilegeList(),
                dataTable.getOrdinalList(),
                data);

        List<List<Object>> excelDataList = new ArrayList<>();
        dataList.forEach(item -> {
            List<Object> list = new ArrayList<>();
            fieldList.forEach(field -> {
                Object object = item.get((String) field.get("value"));
                if (object != null && "formatLongToDate".equals(field.get("format"))) {
                    object = DateUtil.formatTime((Long) object);
                }
                list.add(object);
            });
            excelDataList.add(list);
        });
        FileUtil.downloadExcel(response, dataTable.getName() + ".xlsx", headList, widthList, excelDataList);
    }

    private List<Map<String, Object>> getFieldList(PageCompButtonBO button, List<DataFieldBO> dataFieldList) {
        List<Map<String, Object>> fieldList = new ArrayList<>();
        if (Tool.isNotBlank(button.getFieldsJson())) {
            Type type = new TypeToken<List<Map<String, Object>>>(){}.getType();
            List<Map<String, Object>> fieldMapList = GsonUtil.fromJson(button.getFieldsJson(), type);
            fieldMapList.forEach(fieldMap ->
                dataFieldList.stream()
                        .filter(field -> field.getId().equals(fieldMap.get("id")))
                        .findFirst()
                        .ifPresent(field -> {
                            Map<String, Object> fieldData = new HashMap<>();
                            fieldData.put("name", field.getShowName());
                            if (DataFieldBO.FIELD_TYPE_DATETIME.equals(field.getFieldType())) {
                                fieldData.put("format", "formatLongToDate");
                            }
                            fieldData.put("width", fieldMap.get("width") == null
                                    ? 15 : new BigDecimal(fieldMap.get("width").toString()).intValue());

                            fieldList.add(fieldData);
                        })
            );
        }

        return fieldList;
    }

    private List<Map<String, Object>> getFieldList(DataTableBO dataTable, List<DataFieldBO> dataFieldList) {
        List<Map<String, Object>> fieldList = new ArrayList<>();
        dataTable.getFieldList().forEach(field -> {
            DataFieldBO dataField = dataFieldList.stream()
                    .filter(filter -> filter.getId().equals(field.getFieldId()))
                    .findFirst().orElse(null);
            if (dataField != null && !"图片,视频,附件,地图".contains(dataField.getFieldType())) {
                Map<String, Object> fieldData = new HashMap<>();
                if (DataFieldBO.FIELD_TYPE_RELATION.equals(dataField.getFieldType())) {
                    fieldData.put("value", field.getFieldName() + "_name");
                } else {
                    fieldData.put("value", field.getFieldName());
                }
                fieldData.put("name", Tool.isBlank(field.getAliasName())
                        ? field.getFieldName() : field.getAliasName());
                if (DataFieldBO.FIELD_TYPE_DATETIME.equals(dataField.getFieldType())) {
                    fieldData.put("format", "formatLongToDate");
                }
                fieldData.put("width", field.getWidth() == null ? 15 : Math.abs(field.getWidth() / 10));

                fieldList.add(fieldData);
            }
        });

        return fieldList;
    }


    /**
     * 运行脚本
     */
    @PostMapping("/script/{menuId}/{id}/run")
    public String runScript(
            @PathVariable("menuId") String menuId,
            @PathVariable("id") String id,
            @RequestBody Map<String, Object> data) {
        if(Tool.isBlank(id) || Tool.isBlank(menuId)) {
            return ResultUtil.failureResult("参数错误！");
        }

        codelessService.checkPermit(Constants.getCurrentUser(), menuId);

        Object object = GroovyService.runById(id, data);
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);

        if (object instanceof Message message) {
            if (message.isSuccess()) {
                return ResultUtil.successResult(message.getMessage());
            } else {
                return ResultUtil.failureResult(message.getCode(), message.getMessage());
            }
        }
        return ResultUtil.successResult("执行成功。", object);
    }

    /**
     * 运行脚本
     */
    @PostMapping("/script/{menuId}/{buttonId}/{id}/run")
    public String runButtonScript(
            @PathVariable("menuId") String menuId,
            @PathVariable("buttonId") String buttonId,
            @PathVariable("id") String id,
            @RequestBody Map<String, Object> data) {
        if(Tool.isBlank(menuId) || Tool.isBlank(buttonId) || Tool.isBlank(id)) {
            return ResultUtil.failureResult("参数错误！");
        }

        codelessService.checkPermit(Constants.getCurrentUser(), menuId, buttonId);

        Object object = GroovyService.runById(id, data);
        MessageUtil.publish(Topic.MENU_DATA_CHANGE, menuId);

        if (object instanceof Message message) {
            if (message.isSuccess()) {
                return ResultUtil.successResult(message.getMessage());
            } else {
                return ResultUtil.failureResult(message.getCode(), message.getMessage());
            }
        }
        return ResultUtil.successResult("执行成功。", object);
    }

    /**
     * 运行脚本
     * @param id 脚本ID
     * @param data 脚本参数
     */
    @PostMapping("/script/run/{id}")
    @SuppressWarnings("unchecked")
    public String runScript(@PathVariable("id") String id, @RequestBody Map<String, Object> data) {
        if(Tool.isBlank(id)) {
            return ResultUtil.failureResult("参数错误！");
        }

        Object result = GroovyService.runById(id, (Map<String, Object>) data.get("data"));
        if (result instanceof Message message) {
            if (message.isSuccess()) {
                return ResultUtil.successResult(message.getMessage());
            } else {
                return ResultUtil.failureResult(message.getCode(), message.getMessage());
            }
        }
        return ResultUtil.successResult("执行成功。", result);
    }
}
